/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-env node */
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');
const { execSync } = require('child_process');

const PRODUCT_NAME = 'Earth' // 优先使用package.json的name,没有就用这个
const DEFAULT_BRANCH = 'main'

const VERSION_KEY = 'version';
const BUILD_KEY = 'build';
const MESSAGE_KEY = 'message';
const BRANCH_KEY = 'branch'


const cmds = {
    '-v': VERSION_KEY,
    '-b': BUILD_KEY,
    '-m': MESSAGE_KEY,
    '-branch': BRANCH_KEY,
}

const argv = process.env.npm_config_argv;
let original = []

if (typeof argv === 'string') {
    try {
        const json = JSON.parse(argv);
        original = json.original;
    } catch (error) {
        // empty
    }
}

console.log(original);

const params = {};
let currentParam = null;
for (const arg of original) {
    if (arg.startsWith('-')) {
        currentParam = cmds[arg];
    } else if (currentParam) {
        params[currentParam] = arg;
        currentParam = null;
    }
}


// 输出解析得到的参数
console.log('Parsed parameters:', params);

const version = params[VERSION_KEY];
const buildNumber = params[BUILD_KEY];
const message = params[MESSAGE_KEY];
const branch = params[BRANCH_KEY] || DEFAULT_BRANCH //  main or any branch name

console.log(`\x1b[36m================= branch: "${branch}" ===================\x1b[0m`);

const buildFolderPath = path.join(__dirname, '../build');

const execSyncCmd = (cmd) => {
    console.log(`\x1b[36m================= execute command: "${cmd}" ===================\x1b[0m`);
    return execSync(cmd);
}

const handlePackageJsonFile = () => {
    const packageJsonPath = path.join(__dirname, '../package.json');
    let name;

    try {
        const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
        name = packageJson.name;
        packageJson.scripts = packageJson.scripts || {};

        // 设置version信息
        packageJson.version = version;
        packageJson.buildNumber = buildNumber;

        // 写回 package.json
        fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
        console.log('Release script added to package.json', packageJson);
    } catch (error) {
        console.error('Error updating package.json:', error.message);
    }

    return name || PRODUCT_NAME;
}

// product 函数
function product(name) {
    return new Promise((resole) => {
        // 打包
        if (branch !== DEFAULT_BRANCH) {
            execSyncCmd(`yarn build:${branch}`);
        } else {
            execSyncCmd('yarn build');
        }


        const productFolderPath = path.join(__dirname, '../product');
        const tempFolderPath = path.join(productFolderPath, name);

        try {
            // 1. 创建 product 文件夹
            if (!fs.existsSync(productFolderPath)) {
                fs.mkdirSync(productFolderPath);
            }

            // 2. 将 build 文件夹内容复制到临时文件夹
            fs.mkdirSync(tempFolderPath);

            // 通过递归地遍历 build 文件夹下的内容进行复制
            const copyFiles = (source, destination) => {
                const files = fs.readdirSync(source);
                for (const file of files) {
                    const currentSource = path.join(source, file);
                    const currentDestination = path.join(destination, file);

                    if (fs.lstatSync(currentSource).isDirectory()) {
                        fs.mkdirSync(currentDestination);
                        copyFiles(currentSource, currentDestination);
                    } else {
                        fs.copyFileSync(currentSource, currentDestination, fs.constants.COPYFILE_EXCL);
                    }
                }
            }

            copyFiles(buildFolderPath, tempFolderPath);

            // 3. 压缩文件夹为 zip
            const zipFileName = `${name}_${version}_${buildNumber}.zip`;
            const zipFilePath = path.join(productFolderPath, zipFileName);
            const output = fs.createWriteStream(zipFilePath);
            const archive = archiver('zip', { zlib: { level: 9 } });

            // 修改为包含父文件夹
            archive.directory(tempFolderPath, name);

            archive.pipe(output);
            archive.finalize();

            output.on('close', () => {
                console.log(`Compression completed: \x1b[32m${zipFileName}\x1b[0m, file path: \x1b[32m${zipFilePath}\x1b[0m`);
                // 4. 删除 临时文件夹
                fs.rmSync(tempFolderPath, { recursive: true });
                resole(true)
            });

        } catch (error) {
            console.error('Error in product function:', error.message);
            resole(false)
        }
    });
}

// updateGit 函数
async function updateGit() {
    try {
        // 1. 检查本地 Git 是否有未提交的代码
        const gitStatus = execSyncCmd('git status --porcelain').toString().trim();
        if (gitStatus) {
            console.error('\x1b[31mError: Uncommitted changes present. Commit or discard changes before running the release script.\x1b[0m');
            return false;
        }
        const pre = branch === DEFAULT_BRANCH ? 'release' : branch

        // 2. 切一个新的分支 release_${version}_${buildNumber}
        const branchName = `${pre}_${version}_${buildNumber}`;
        execSyncCmd(`git checkout -b ${branchName}`);

        const name = handlePackageJsonFile();
        console.log(`================= product name: ${name} ===================`);
        // 3. 执行 product 函数
        const result = await product(name);
        if (!result) {
            return false
        }

        // 4. 提交 Git，并推送到远程
        const m = message ? `, message: ${message}` : '';
        const commitMessage = `${name} ${pre}, version: ${version}, build:${buildNumber}${m}`;
        execSyncCmd(`git add . && git commit -m "${commitMessage}"`);
        // execSyncCmd(`git push origin ${branchName}`);

        // 5. 打 tag
        execSyncCmd(`git tag -a telegram_mini_app-${pre}-v${version}.${buildNumber} -m "version ${version}, build: ${buildNumber}${m}"`)
        execSyncCmd(`git push origin telegram_mini_app-${pre}-v${version}.${buildNumber}`)

        console.log('\x1b[32mGit update completed.\x1b[0m');
        return true

    } catch (error) {
        console.error('Error in updateGit function:', error.message);
        return false
    }
}


// update file to github
// GitHub 相关信息
const owner = 'pte2024';
const repo = 'earth-minapp';
const token = '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'; // Expires on Sat, Sep 21 2024.  settings -> Developer Settings -> Personal access token

let Octokit;
let octokit;

// 递归遍历文件夹并获取文件列表
function getFilesList(dirPath) {
    console.log(`read build file: ${dirPath}`)
    const filesList = [];
    const files = fs.readdirSync(dirPath);
    files.forEach(file => {
        const filePath = path.join(dirPath, file);
        const stats = fs.statSync(filePath);
        if (stats.isFile()) {
            filesList.push(filePath);
        } else if (stats.isDirectory()) {
            const subFiles = getFilesList(filePath);
            filesList.push(...subFiles);
        }
    });
    return filesList;
}

// 创建文件 blob
async function createBlob(filePath) {
    console.log(`create blob: ${filePath}`)
    const content = fs.readFileSync(filePath);
    const { data } = await octokit.request('POST /repos/{owner}/{repo}/git/blobs', {
        owner: owner,
        repo: repo,
        content: Buffer.from(content).toString('base64'),
        encoding: 'base64'
    });
    return data.sha;
}

// 创建文件树
async function createTree(files) {
    console.log('create files tree ...')
    const tree = [];
    for (const filePath of files) {
        const fileName = path.relative(buildFolderPath, filePath).split(path.sep).join('/');
        if (fileName === '.DS_Store') {
            continue
        }
        const sha = await createBlob(filePath);
        tree.push({
            path: fileName,
            mode: '100644',
            type: 'blob',
            sha: sha
        });
    }

    const ignore = await ignorePath('resources');
    if (ignore?.path) {
        tree.push({
            path: ignore.path,
            mode: ignore.mode,
            type: ignore.type,
            sha: ignore.sha
        })
    }

    const { data } = await octokit.request('POST /repos/{owner}/{repo}/git/trees', {
        owner: owner,
        repo: repo,
        tree: tree
    });
    return data.sha;
}

// 创建提交
async function createCommit(treeSha) {
    const message = `${version}.${buildNumber}`
    console.log(`create commit..., message: ${message}`)
    const { data } = await octokit.request('GET /repos/{owner}/{repo}/git/refs/{ref}', {
        owner: owner,
        repo: repo,
        ref: `heads/${branch}`
    });
    const refSha = data.object.sha;
    const { data: commitData } = await octokit.request('GET /repos/{owner}/{repo}/git/commits/{commit_sha}', {
        owner: owner,
        repo: repo,
        commit_sha: refSha
    });
    const { data: newCommitData } = await octokit.request('POST /repos/{owner}/{repo}/git/commits', {
        owner: owner,
        repo: repo,
        message,
        tree: treeSha,
        parents: [commitData.sha]
    });
    return newCommitData.sha;
}

// 更新分支引用
async function updateRef(commitSha) {
    console.log('push...')
    await octokit.request('PATCH /repos/{owner}/{repo}/git/refs/{ref}', {
        owner: owner,
        repo: repo,
        ref: `heads/${branch}`,
        sha: commitSha
    });
}

async function getRemoteTree() {
    const { data } = await octokit.request('GET /repos/{owner}/{repo}/git/trees/{tree_sha}', {
        owner: owner,
        repo: repo,
        tree_sha: branch // 或者你的分支名称
    });
    return data.tree;
}

async function ignorePath(path) {
    const tree = await getRemoteTree();
    return tree.find(item => item.path === path)
}

// 主函数：上传 build 文件夹下的所有文件并创建一个提交
async function uploadBuildFiles() {
    try {
        const files = getFilesList(buildFolderPath);
        const treeSha = await createTree(files);
        const commitSha = await createCommit(treeSha);
        await updateRef(commitSha);
        console.log('\x1b[32mFiles uploaded to GitHub successfully!\x1b[0m');
    } catch (error) {
        console.log(error)
        console.error('Failed to upload files to GitHub:', error.message);
    }
}

const getOctokit = async () => {
    try {
        // 尝试使用 CommonJS 的 require
        Octokit = require('@octokit/core');
    } catch (error) {
        // 如果失败，则使用动态 import
        const octokitModule = await import('@octokit/core');
        Octokit = octokitModule.Octokit;
    }
    return Octokit;
};


const uploadToGit = async () => {
    Octokit = await getOctokit()
    octokit = new Octokit({ auth: token });
    await uploadBuildFiles();
}

const main = async () => {
    // update to gitee
    const success = await updateGit();

    // upload file to github
    // if upload to github failed, and reason is like 'Connection closed by remote host...'， you can
    //      1、 grep github /etc/hosts
    //      2、 find a valid ip in 'https://api.github.com/meta'
    //      3、 replece and save
    success && await uploadToGit()
}

main()






